home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / Math.p < prev    next >
Encoding:
Text File  |  1995-10-12  |  39.8 KB  |  1,562 lines  |  [TEXT/PJMM]

  1. unit Math;
  2.  
  3. interface
  4.  
  5.     uses
  6.  
  7.         Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils,Resources, Errors, Palettes, globals, Utilities, RealUtils, Graphics, Camera, Filters, Lut, fft;
  8.  
  9.  
  10.     procedure SetPasteMode (item: integer);
  11.     procedure DoMouseDownInPasteControl (loc: point);
  12.     procedure ShowPasteControl;
  13.     procedure DrawPasteControl;
  14.     procedure DoArithmetic (MenuItem: integer; constant: extended);
  15.     function GetMathRoi(Src1PicNum, Src2PicNum:integer; var roi:rect):boolean;
  16.     procedure DoMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
  17.     procedure DoPasteMath;
  18.     procedure DoImageMath;
  19.     function GetInfoPtr (PicN: integer): InfoPtr;
  20.  
  21.  
  22. implementation
  23.  
  24.     const
  25.         Src1Item = 7;
  26.         Src2Item = 8;
  27.         OpItem = 9;
  28.  
  29.  
  30.     procedure DoPasteMath;
  31.         const
  32.             PixelsPerUpdate = 15000;
  33.         var
  34.             nrows, ncols, hSrcStart, vSrcStart, hDstStart, vDstStart: integer;
  35.             SaveInfo: InfoPtr;
  36.             h, v, vDst, PixelCount, offset: integer;
  37.             Src, Dst: LineType;
  38.             tmp, range, min, max, StartTicks: LongInt;
  39.             x, xmax, xmin, xrange, xxscale: extended;
  40.     begin
  41.         if TooWide then
  42.             exit(DoPasteMath);
  43.         ShowWatch;
  44.         OpPending := false;
  45.         WhatToUndo := UndoPaste;
  46.         KillRoi;
  47.         with info^.RoiRect do begin
  48.                 ncols := right - left;
  49.                 nrows := bottom - top;
  50.                 hDstStart := left;
  51.                 vDstStart := top;
  52.             end;
  53.         with ClipBufInfo^.RoiRect do begin
  54.                 hSrcStart := left;
  55.                 vSrcStart := top;
  56.             end;
  57.         if hDstStart < 0 then begin
  58.                 offset := -hDstStart;
  59.                 hDstStart := 0;
  60.                 hSrcStart := hSrcStart + offset;
  61.                 ncols := ncols - offset;
  62.             end;
  63.         if vDstStart < 0 then begin
  64.                 offset := -vDstStart;
  65.                 vDstStart := 0;
  66.                 vSrcStart := vSrcStart + offset;
  67.                 nrows := nrows - offset;
  68.             end;
  69.         with info^.PicRect do begin
  70.                 if hDstStart + ncols > right then
  71.                     ncols := right - hDstStart;
  72.                 if vDstStart + nrows > bottom then
  73.                     nrows := bottom - vDstStart;
  74.             end;
  75.         SaveInfo := info;
  76.         vDst := vDstStart;
  77.         min := 999999;
  78.         max := -999999;
  79.         xmin := 999999.0;
  80.         xmax := -999999.0;
  81.         StartTicks := TickCount;
  82.        {First pass to find result range}
  83.         if ScaleArithmetic then begin
  84.                 for v := vSrcStart to vSrcStart + nRows - 1 do begin
  85.                         Info := ClipBufInfo;
  86.                         GetLine(hSrcStart, v, nCols, Src);
  87.                         Info := SaveInfo;
  88.                         GetLine(hDstStart, vDst, nCols, Dst);
  89.                         case CurrentOp of
  90.                             AddOp:  begin
  91.                                     for h := 0 to nCols - 1 do begin
  92.                                             tmp := Src[h] + Dst[h];
  93.                                             if tmp > max then
  94.                                                 max := tmp;
  95.                                             if tmp < Min then
  96.                                                 min := tmp;
  97.                                         end;
  98.                                 end;
  99.                             SubtractOp:  begin
  100.                                     for h := 0 to nCols - 1 do begin
  101.                                             tmp := Dst[h] - Src[h];
  102.                                             if tmp > max then
  103.                                                 max := tmp;
  104.                                             if tmp < Min then
  105.                                                 min := tmp;
  106.                                         end;
  107.                                 end;
  108.                             MultiplyOp:  begin
  109.                                     for h := 0 to nCols - 1 do begin
  110.                                             tmp := Dst[h];
  111.                                             tmp := tmp * Src[h];
  112.                                             if tmp > max then
  113.                                                 max := tmp;
  114.                                             if tmp < min then
  115.                                                 min := tmp;
  116.                                         end;
  117.                                 end;
  118.                             DivideOp:  begin
  119.                                     for h := 0 to nCols - 1 do begin
  120.                                             tmp := Src[h];
  121.                                             if tmp = 0 then
  122.                                                 tmp := 1;
  123.                                             x := Dst[h] / tmp;
  124.                                             if x > xmax then begin
  125.                                                     xmax := x;
  126.                                                 end;
  127.                                             if x < xmin then
  128.                                                 xmin := x;
  129.                                         end;
  130.                                 end;
  131.                         end;
  132.                         vDst := vDst + 1;
  133.                     end;
  134.                 vDst := vDstStart;
  135.                 if CurrentOp = DivideOp then begin
  136.                         xrange := xmax - xmin;
  137.                         if xrange <> 0.0 then
  138.                             xxscale := 256.0 / xrange
  139.                         else
  140.                             xxscale := 1;
  141.                     end
  142.                 else
  143.                     range := max - min;
  144.             end; {if ScaleArithmetic=true}
  145.         PixelCount := 0;
  146.        {Second pass to do arithmetic and scaling}
  147.         for v := vSrcStart to vSrcStart + nRows - 1 do begin
  148.                 Info := ClipBufInfo;
  149.                 GetLine(hSrcStart, v, nCols, Src);
  150.                 Info := SaveInfo;
  151.                 GetLine(hDstStart, vDst, nCols, Dst);
  152.                 case CurrentOp of
  153.                     AddOp: 
  154.                         if ScaleArithmetic then
  155.                             for h := 0 to nCols - 1 do begin
  156.                                     tmp := Dst[h] + Src[h] - min;
  157.                                     if range <> 0 then
  158.                                         tmp := tmp * 256 div range
  159.                                     else
  160.                                         tmp := BackgroundIndex;
  161.                                     if tmp > 255 then
  162.                                         dst[h] := 255
  163.                                     else
  164.                                         dst[h] := tmp;
  165.                                 end
  166.                         else
  167.                             for h := 0 to nCols - 1 do begin
  168.                                     tmp := Dst[h] + Src[h];
  169.                                     if tmp > 255 then
  170.                                         dst[h] := 255
  171.                                     else
  172.                                         dst[h] := tmp;
  173.                                 end;
  174.                     SubtractOp: 
  175.                         if ScaleArithmetic then
  176.                             for h := 0 to nCols - 1 do begin
  177.                                     tmp := Dst[h] - Src[h] - min;
  178.                                     if range <> 0 then
  179.                                         tmp := tmp * 256 div range
  180.                                     else
  181.                                         tmp := BackgroundIndex;
  182.                                     if tmp > 255 then
  183.                                         dst[h] := 255
  184.                                     else
  185.                                         dst[h] := tmp;
  186.                                 end
  187.                         else
  188.                             for h := 0 to nCols - 1 do begin
  189.                                     tmp := Dst[h] - Src[h];
  190.                                     if tmp < 0 then
  191.                                         dst[h] := 0
  192.                                     else
  193.                                         dst[h] := tmp;
  194.                                 end;
  195.                     MultiplyOp: 
  196.                         if ScaleArithmetic then
  197.                             for h := 0 to nCols - 1 do begin
  198.                                     tmp := Dst[h];
  199.                                     tmp := tmp * Src[h] - min;
  200.                                     if range <> 0 then
  201.                                         tmp := tmp * 256 div range
  202.                                     else
  203.                                         tmp := BackgroundIndex;
  204.                                     if tmp > 255 then
  205.                                         dst[h] := 255
  206.                                     else
  207.                                         dst[h] := tmp;
  208.                                 end
  209.                         else
  210.                             for h := 0 to nCols - 1 do begin
  211.                                     tmp := Dst[h];
  212.                                     tmp := tmp * Src[h];
  213.                                     if tmp > 255 then
  214.                                         dst[h] := 255
  215.                                     else
  216.                                         dst[h] := tmp;
  217.                                 end;
  218.                     DivideOp: 
  219.                         if ScaleArithmetic then
  220.                             for h := 0 to nCols - 1 do begin
  221.                                     tmp := Src[h];
  222.                                     if tmp = 0 then
  223.                                         tmp := 1;
  224.                                     x := Dst[h] / tmp - xmin;
  225.                                     if xrange <> 0.0 then
  226.                                         tmp := trunc(x * xxscale)
  227.                                     else
  228.                                         tmp := BackgroundIndex;
  229.                                     if tmp > 255 then
  230.                                         tmp := 255;
  231.                                     if tmp < 0 then
  232.                                         tmp := 0;
  233.                                     dst[h] := tmp;
  234.                                 end
  235.                         else
  236.                             for h := 0 to nCols - 1 do begin
  237.                                     tmp := Src[h];
  238.                                     if tmp = 0 then
  239.                                         tmp := 1;
  240.                                     dst[h] := Dst[h] div tmp;
  241.                                 end;
  242.                 end;
  243.                 PutLine(hDstStart, vDst, nCols, Dst);
  244.                 vDst := vDst + 1;
  245.                 PixelCount := PixelCount + ncols;
  246.                 if PixelCount > PixelsPerUpdate then begin
  247.                         UpdateScreen(info^.RoiRect);
  248.                         if CommandPeriod then begin
  249.                                 UpdateScreen(info^.RoiRect);
  250.                                 beep;
  251.                                 exit(DoPasteMath)
  252.                             end;
  253.                         PixelCount := 0;
  254.                     end;
  255.             end;
  256.         with info^ do begin
  257.                 ShowTime(StartTicks, RoiRect, '');
  258.                 UpdateScreen(RoiRect);
  259.             end;
  260.     end;
  261.  
  262.  
  263.     procedure SetPasteMode (item: integer);
  264.         var
  265.             SavePort: GrafPtr;
  266.             BlendColor: rgbColor;
  267.     begin
  268.         if not macro then begin
  269.                 SetForegroundColor(BlackIndex);
  270.                 SetBackGroundColor(WhiteIndex);
  271.             end;
  272.         case Item of
  273.             CopyModeItem: 
  274.                 PasteTransferMode := SrcCopy;
  275.             AndItem: 
  276.                 PasteTransferMode := NotSrcBic; {And}
  277.             OrItem: 
  278.                 PasteTransferMode := SrcOr;
  279.             XorItem: 
  280.                 PasteTransferMode := SrcXor;
  281.             ReplaceItem: 
  282.                 PasteTransferMode := Transparent;
  283.             BlendItem:  begin
  284.                     GetPort(SavePort);
  285.                     with BlendColor do begin
  286.                             red := 32767;
  287.                             blue := 32767;
  288.                             green := 32767;
  289.                         end;
  290.                     SetPort(GrafPtr(info^.osPort));
  291.                     OpColor(BlendColor);
  292.                     SetPort(SavePort);
  293.                     PasteTransferMode := Blend;
  294.                 end;
  295.             otherwise
  296.         end; {case}
  297.     end;
  298.  
  299.  
  300.     function GetTransferModeItem: integer;
  301.     begin
  302.         case PasteTransferMode of
  303.             SrcCopy: 
  304.                 GetTransferModeItem := CopyModeItem;
  305.             NotSrcBic: 
  306.                 GetTransferModeItem := AndItem;
  307.             SrcOr: 
  308.                 GetTransferModeItem := OrItem;
  309.             SrcXor: 
  310.                 GetTransferModeItem := XorItem;
  311.             Transparent: 
  312.                 GetTransferModeItem := ReplaceItem;
  313.             Blend: 
  314.                 GetTransferModeItem := BlendItem;
  315.         end;
  316.     end;
  317.  
  318.  
  319.     procedure DrawPasteControl;
  320.         const
  321.             bWidth = 64;
  322.             bHeight = 14;
  323.             vinc = 18;
  324.             bhloc = 114;
  325.             bvloc = 6;
  326.         var
  327.             tPort: GrafPtr;
  328.             i, hloc, vloc, item: integer;
  329.             tType: pcItemType;
  330.             tRect, TriangleRect: rect;
  331.             ItemStr: str255;
  332.     begin
  333.         GetPort(tPort);
  334.         SetPort(PasteControl);
  335.         with PcItem[1] do begin
  336.                 SetRect(r, 15, 22, 95, 40);
  337.                 itype := pcPopupMenu;
  338.                 str := 'Transfer Mode';
  339.             end;
  340.         with pcItem[2] do begin
  341.                 SetRect(r, 88, 50, 100, 62);
  342.                 itype := pcCheckBox;
  343.                 str := 'Scale Math';
  344.             end;
  345.         with pcItem[3] do begin
  346.                 SetRect(r, 88, 65, 100, 77);
  347.                 itype := pcCheckBox;
  348.                 str := 'Live Paste';
  349.             end;
  350.         hloc := bhloc;
  351.         vloc := bvloc;
  352.         tType := pcButton;
  353.         with pcItem[4] do begin
  354.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  355.                 itype := tType;
  356.                 str := 'Add';
  357.             end;
  358.         vloc := vloc + vinc;
  359.         with pcItem[5] do begin
  360.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  361.                 itype := tType;
  362.                 str := 'Subtract';
  363.             end;
  364.         vloc := vloc + vinc;
  365.         with pcItem[6] do begin
  366.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  367.                 itype := tType;
  368.                 str := 'Multiply';
  369.             end;
  370.         vloc := vloc + vinc;
  371.         with pcItem[7] do begin
  372.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  373.                 itype := tType;
  374.                 str := 'Divide';
  375.             end;
  376.         TextFont(SystemFont);
  377.         TextSize(12);
  378.         for i := 1 to npcItems do
  379.             with pcItem[i] do
  380.                 case iType of
  381.                     pcPopupMenu: 
  382.                         with r do begin
  383.                                 MoveTo(r.left - 10, r.top - 4);
  384.                                 DrawString(str);
  385.                                 DrawDropBox(r);
  386.                                 item := GetTransferModeItem;
  387.                                 GetMenuItemText(TransferModeMenuH, item, ItemStr);
  388.                                 MoveTo(left + 13, bottom - 5);
  389.                                 DrawString(ItemStr);
  390.                             end;
  391.                     pcCheckBox: 
  392.                         with r do begin
  393.                                 MoveTo(left - StringWidth(str) - 4, bottom - 2);
  394.                                 DrawString(str);
  395.                                 EraseRect(r);
  396.                                 FrameRect(r);
  397.                                 if ((i = 2) and ScaleArithmetic) or ((i = 3) and LivePasteMode) then begin
  398.                                         MoveTo(left, top);
  399.                                         LineTo(right - 1, bottom - 1);
  400.                                         MoveTo(left, bottom - 1);
  401.                                         LineTo(right - 1, top);
  402.                                     end;
  403.                             end;
  404.                     pcButton:  begin
  405.                             FrameRoundRect(r, 6, 6);
  406.                             with r do
  407.                                 MoveTo(left + ((right - left) - StringWidth(str)) div 2, bottom - 3);
  408.                             DrawString(str);
  409.                         end;
  410.                 end; {case}
  411.         SetPort(tPort);
  412.     end;
  413.  
  414.  
  415.     procedure DoMouseDownInPasteControl; {(loc:point)}
  416.         var
  417.             nItem, i, MenuItem: integer;
  418.             tr: rect;
  419.     begin
  420.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  421.                 PutError('Paste Control is only available during paste operations.');
  422.                 exit(DoMouseDownInPasteControl);
  423.             end;
  424.         SetPort(PasteControl);
  425.         GlobalToLocal(loc);
  426.         nItem := 0;
  427.         for i := 1 to npcItems do
  428.             if PtInRect(loc, pcItem[i].r) then
  429.                 nitem := i;
  430.         if nItem > 0 then begin
  431.                 case pcItem[nItem].itype of
  432.                     pcPopUpMenu: 
  433.                         with pcItem[1].r do begin
  434.                                 MenuItem := PopUpMenu(TransferModeMenuH, left, top, GetTransferModeItem);
  435.                                 SetPasteMode(MenuItem);
  436.                             end;
  437.                     pcCheckBox:  begin
  438.                             tr := pcItem[nItem].r;
  439.                             InsetRect(tr, 1, 1);
  440.                             FrameRect(tr);
  441.                             if nitem = 2 then
  442.                                 ScaleArithmetic := not ScaleArithmetic;
  443.                             if nitem = 3 then begin
  444.                                     LivePasteMode := not LivePasteMode;
  445.                                     if LivePasteMode then begin
  446.                                             ExternalTrigger := false;
  447.                                             UpdateVideoControl
  448.                                         end;
  449.                                 end;
  450.                         end;
  451.                     pcButton:  begin
  452.                             InvertRoundRect(pcItem[nitem].r, 6, 6);
  453.                             while Button and (nitem > 0) do begin
  454.                                     GetMouse(loc);
  455.                                     if not PtInRect(loc, pcItem[nitem].r) then begin
  456.                                             InvertRoundRect(pcItem[nitem].r, 6, 6);
  457.                                             nItem := 0;
  458.                                         end;
  459.                                 end;
  460.                         end;
  461.                 end; {case}
  462.                 repeat
  463.                 until not button;
  464.                 if nItem > 0 then
  465.                     with pcItem[nitem] do begin
  466.                             case itype of
  467.                                 pcPopupMenu: 
  468.                                     ;
  469.                                 pcCheckBox:  begin
  470.                                     end;
  471.                                 pcButton:  begin
  472.                                         InvertRoundRect(pcItem[nitem].r, 6, 6);
  473.                                         if info^.RoiType = RectRoi then begin
  474.                                                 case nitem of
  475.                                                     4: 
  476.                                                         CurrentOp := AddOp;
  477.                                                     5: 
  478.                                                         CurrentOp := SubtractOp;
  479.                                                     6: 
  480.                                                         CurrentOp := MultiplyOp;
  481.                                                     7: 
  482.                                                         CurrentOp := DivideOp;
  483.                                                 end;
  484.                                                 DoPasteMath;
  485.                                             end; {if}
  486.                                     end; {pcButton}
  487.                             end; {case}
  488.                         end; {with}
  489.             end; {if nitem>0}
  490.         if LivePasteMode and (((WhatsOnClip <> CameraPic) and (WhatsOnClip <> LivePic)) or (FrameGrabber =NoFrameGrabber)) then begin
  491.                 PutError('"Live Paste" requires that a rectangular selection be first copied from the Camera window to the Clipboard.');
  492.                 LivePasteMode := false;
  493.             end;
  494.         if LivePasteMode and (info^.PictureType = FrameGrabberType) then begin
  495.                 PutError('Live pasting into the Camera window is not supported.');
  496.                 LivePasteMode := false;
  497.             end;
  498.         DrawPasteControl;
  499.     end;
  500.  
  501.  
  502.     procedure ShowPasteControl;
  503.         var
  504.             tPort: GrafPtr;
  505.             trect: rect;
  506.             wp: ^WindowPtr;
  507.     begin
  508.         SetRect(trect, PasteControlLeft, PasteControlTop, PasteControlLeft + pcwidth, PasteControlTop + pcheight);
  509.         PasteControl := NewWindow(nil, trect, 'Paste Control', true, rDocProc, nil, true, 0);
  510.         WindowPeek(PasteControl)^.WindowKind := PasteControlKind;
  511.         wp := pointer(GhostWindow);
  512.         wp^ := PasteControl;
  513.         PasteTransferMode := SrcCopy;
  514.         LivePasteMode := false;
  515.     end;
  516.  
  517.  
  518.     function GetRealC (message: str255; default: extended; precision: integer; var Canceled: boolean): extended;
  519.         const
  520.             NumberID = 3;
  521.             CalibrateID = 5;
  522.         var
  523.             mylog: DialogPtr;
  524.             item: integer;
  525.     begin
  526.         InitCursor;
  527.         ParamText(message, '', '', '');
  528.         mylog := GetNewDialog(290, nil, pointer(-1));
  529.         SetDReal(MyLog, NumberID, default, precision);
  530.         SetDlogItem(MyLog, CalibrateID, ord(RealArithmetic));
  531.         SelectdialogItemText(MyLog, NumberID, 0, 32767);
  532.         OutlineButton(MyLog, ok, 16);
  533.         repeat
  534.             ModalDialog(nil, item);
  535.             if item = CalibrateID then begin
  536.                 RealArithmetic := not RealArithmetic;
  537.                 SetDlogItem(MyLog, CalibrateID, ord(RealArithmetic));
  538.             end;
  539.         until (item = ok) or (item = cancel);
  540.         if item = ok then begin
  541.                 GetRealC := GetDReal(MyLog, NumberID);
  542.                 Canceled := false;
  543.             end
  544.         else begin
  545.                 GetRealC := default;
  546.                 Canceled := true;
  547.             end;
  548.         DisposeDialog(mylog);
  549.     end;
  550.  
  551.  
  552.     procedure DoArithmetic (MenuItem: integer; constant: extended);
  553.         var
  554.             table: LookupTable;
  555.             i, iConst, pNum, digits: integer;
  556.             tmp: LongInt;
  557.             LogScale: extended;
  558.             Canceled: boolean;
  559.             result: str255;
  560.     begin
  561.         canceled := false;
  562.         if info^.fit <> Uncalibrated then
  563.             RealArithmetic := true;
  564.         if not macro then
  565.             case menuItem of
  566.                 AddItem: 
  567.                     constant := GetRealC('Constant to add:', 25, 0, Canceled);
  568.                 SubtractItem: 
  569.                     constant := GetRealC('Constant to subtract:', 25, 0, Canceled);
  570.                 MultiplyItem:  begin
  571.                         constant := GetRealC('Constant to multiply by:', 1.25, 2, Canceled);
  572.                         if constant < 0.0 then begin
  573.                                 PutError('Constant must be positive.');
  574.                                 exit(DoArithmetic);
  575.                             end;
  576.                     end;
  577.                 DivideItem:  begin
  578.                         constant := GetRealC('Constant to divide by:', 1.25, 2, Canceled);
  579.                         if constant <= 0.0 then begin
  580.                                 PutError('Constant must be nonzero and positive.');
  581.                                 exit(DoArithmetic);
  582.                             end;
  583.                     end;
  584.                 AndItem2: 
  585.                     constant := GetInt('AND image with:', 240, Canceled);
  586.                 OrItem2: 
  587.                     constant := GetInt('OR image with:', 31, Canceled);
  588.                 XorItem2: 
  589.                     constant := GetInt('XOR image with:', 31, Canceled);
  590.                 LogItem:  begin
  591.                         if not CheckCalibration then
  592.                             exit(DoArithmetic);
  593.                         constant := 0.0;
  594.                         LogScale := 255.0 / ln(255.0);
  595.                     end;
  596.             end; {case}
  597.         if Canceled then
  598.             exit(DoArithmetic);
  599.         if RealArithmetic and (MenuItem >= AddItem) and (MenuItem <= DivideItem)  and not macro then begin
  600.             if constant < 1.0 then
  601.                 digits := 3
  602.             else if constant <10.0 then
  603.                 digits := 2
  604.             else digits := 1;
  605.             if trunc(constant) = constant then
  606.                 digits := 0;
  607.             with info^ do case MenuItem of
  608.                 AddItem: begin
  609.                         MathGain := 1.0;
  610.                         MathOffset := constant;
  611.                         result := StringOf(title, '+', constant:1:digits) 
  612.                     end;
  613.                 SubtractItem: begin
  614.                         MathGain := 1.0;
  615.                         MathOffset := -constant;
  616.                         result := StringOf(title, '-', constant:1:digits) 
  617.                     end;
  618.                 MultiplyItem: begin
  619.                         MathGain := constant;
  620.                         MathOffset := 0.0;
  621.                         result := StringOf(title, '*', constant:1:digits) 
  622.                     end;
  623.                 DivideItem: begin
  624.                         MathGain := 1.0 / constant;
  625.                         MathOffset := 0.0;
  626.                         result := StringOf(title, '/', constant:1:digits) 
  627.                     end;
  628.             end;
  629.             pNum := info^.picNum;
  630.             with info^.PicRect do
  631.                 if not NewRealWindow(result, right-left, bottom-top) then
  632.                 exit(DoArithmetic);
  633.             CurrentMathOp := CopyMath;
  634.             RealImageMath := true;
  635.             DoMath(pNum, pNum, Info, info^.picRect);
  636.             exit(DoArithmetic);
  637.         end;
  638.         iconst := trunc(constant);
  639.         for i := 0 to 255 do begin
  640.                 case MenuItem of
  641.                     AddItem: 
  642.                         tmp := round(i + constant);
  643.                     SubtractItem: 
  644.                         tmp := round(i - constant);
  645.                     MultiplyItem: 
  646.                         tmp := round(i * constant);
  647.                     DivideItem: 
  648.                         tmp := round(i / constant);
  649.                     AndItem2: 
  650.                         tmp := band(i, iconst);
  651.                     OrItem2: 
  652.                         tmp := bor(i, iconst);
  653.                     XorItem2:
  654.                         tmp := bxor(i, iconst);
  655.                     LogItem:
  656.                         if i = 0 then
  657.                             tmp := 0
  658.                         else
  659.                             tmp := round(ln(i) * LogScale);
  660.                 end;
  661.                 if tmp < 0 then
  662.                     tmp := 0;
  663.                 if tmp > 255 then
  664.                     tmp := 255;
  665.                 table[i] := tmp;
  666.             end;
  667.         ApplyTable(table);
  668.         if (MenuItem >= AddItem) and (MenuItem <= DivideItem) then
  669.             RemoveDensityCalibration;
  670.     end;
  671.  
  672.  
  673.     function GetInfoPtr (PicN: integer): InfoPtr;
  674.   {Converts a pic number or pid number to an Info ptr.}
  675.         var
  676.             i: integer;
  677.     begin
  678.         i := 0;
  679.         while (PicN < 0) and (i < nPics) do begin
  680.                 i := i + 1;
  681.                 if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = PicN then
  682.                     PicN := i;
  683.             end;
  684.         if (PicN >= 1) and (PicN <= nPics) then
  685.             GetInfoPtr := pointer(WindowPeek(PicWindow[PicN])^.RefCon)
  686.         else
  687.             GetInfoPtr := nil;
  688.     end;
  689.  
  690.  
  691.     procedure ShowRoi(roi:rect);
  692.     begin
  693.         with roi do ShowMessage(StringOf(left:4, top:4, right-left:4, bottom-top:4));
  694.         wait(200);
  695.     end;
  696.  
  697.  
  698.     function GetMathRoi(Src1PicNum, Src2PicNum:integer; var roi:rect):boolean;
  699.         var
  700.             Src1Info, Src2Info: InfoPtr;
  701.             ignore:boolean;
  702.     begin
  703.         KillRoi;
  704.         GetMathRoi:=false;
  705.         Src1Info := GetInfoPtr(Src1PicNum);
  706.         Src2Info := GetInfoPtr(Src2PicNum);
  707.          if (Src1Info = nil) or (Src2Info = nil) then begin
  708.                 PutError('Bad pic num or pid num.');
  709.                 AbortMacro;
  710.                 exit(GetMathRoi);
  711.             end;
  712.         roi := Src1Info^.PicRect;
  713.         ignore := SectRect(roi, Src2Info^.PicRect, roi);
  714.         GetMathRoi:=true;
  715.     end;
  716.     
  717.     
  718.  
  719.     procedure DoFFTMath (Src1Info, Src2Info, DstInfo:InfoPtr);
  720.     {Does image math when both source images are FFTs.}
  721.     var
  722.         i, StartTicks: LongInt;
  723.         r, c, modAdd, rowMod, colMod, maxN: LongInt;
  724.         H2e, H2o, mag: real;
  725.         h1, h2, Out: rImagePtr;
  726.         roi:rect;
  727.     begin
  728.         maxN := Src1Info^.pixelsPerLine;
  729.         h1 :=  rImagePtr(Src1Info^.DataH^);
  730.         h2 :=  rImagePtr(Src2Info^.DataH^);
  731.         out := rImagePtr(DstInfo^.DataH^);
  732.         StartTicks := TickCount;
  733.         case CurrentMathOp of
  734.             MulMath, cMulMath: {Point by point Hartley multiplication or conjugate multiplication}
  735.                 for r := 0 to maxN - 1 do begin
  736.                     rowMod := (maxN - r) mod maxN;
  737.                     for c := 0 to maxN - 1 do begin
  738.                         colMod := (maxN - c) mod maxN;
  739.                         H2e := (h2^[r * maxN + c] + h2^[rowMod * maxN + colMod]) / 2;
  740.                         H2o := (h2^[r * maxN + c] - h2^[rowMod * maxN + colMod]) / 2;
  741.                         if CurrentMathOp = cMulMath then
  742.                             Out^[r * maxN + c] := h1^[r * maxN + c] * H2e - h1^[rowMod * maxN + colMod] * H2o
  743.                         else
  744.                             Out^[r * maxN + c] := h1^[r * maxN + c] * H2e + h1^[rowMod * maxN + colMod] * H2o;
  745.                     end;
  746.                 end; {for}
  747.             DivMath:  {Point by point Hartley division}
  748.                 for r := 0 to maxN - 1 do begin
  749.                     rowMod := (maxN - r) mod maxN;
  750.                     for c := 0 to maxN - 1 do begin
  751.                         colMod := (maxN - c) mod maxN;
  752.                         mag := H2^[r * maxN + c] * H2^[r * maxN + c] + H2^[rowMod * maxN + colMod] * H2^[rowMod * maxN + colMod];
  753.                         if mag < 1e-20 then
  754.                             mag := 1e-20;
  755.                         H2e := (H2^[r * maxN + c] + H2^[rowMod * maxN + colMod]);
  756.                         H2o := (H2^[r * maxN + c] - H2^[rowMod * maxN + colMod]);
  757.                         Out^[r * maxN + c] := (H1^[r * maxN + c] * H2e - H1^[rowMod * maxN + colMod] * H2o) / mag;
  758.                     end;
  759.                 end; {for}
  760.         end; {case}
  761.         info := dstInfo;
  762.         DisplayPowerSpectrum(out);
  763.         SetFFTWindowName(false);
  764.         hunlock(src1Info^.dataH);
  765.         hunlock(src2Info^.dataH);        
  766.         hunlock(dstInfo^.dataH);
  767.         SetRect(roi, 0, 0, maxN, maxN);
  768.         ShowTime(StartTicks, roi, '');
  769.     end; {DoFFTMath}
  770.  
  771.     
  772.     
  773.     procedure DoRealRealMath (Src1Info, Src2Info, DstInfo:InfoPtr; roi:rect);
  774.     {Does image math when both source images are real.}
  775.         var
  776.             nrows, ncols, hStart, vStart: LongInt;
  777.             h, v, i: LongInt;
  778.             tmp, tmp1, tmp2, StartTicks: LongInt;
  779.             SaveRow:LongInt;
  780.             NextUpdate: LongInt;
  781.             MaskRect:rect;
  782.             min, max, x, scale, x1, x2: extended;
  783.             s1Data, s2Data, rData: rImagePtr;
  784.             base: LongInt;
  785.             isFFT: boolean;
  786.             saveInfo: InfoPtr;
  787.  
  788.     begin
  789.         with src1Info^ do begin
  790.             if DataH = nil then begin
  791.                 saveInfo := info;
  792.                 info := src1Info;
  793.                 if not ConvertToReal then begin
  794.                     info := saveInfo;
  795.                     exit(DoRealRealMath)
  796.                 end;
  797.             end;
  798.             hlock(DataH);
  799.             s1Data := rImagePtr(DataH^);
  800.             isFFT := pos('FFT', title) = 1;
  801.         end;
  802.         if (CurrentMathOp <> CopyMath) then
  803.             with src2Info^ do begin
  804.                 if DataH = nil then begin
  805.                     saveInfo := info;
  806.                     info := src2Info;
  807.                     if not ConvertToReal then begin
  808.                         info := saveInfo;
  809.                         hunlock(DataH);
  810.                         exit(DoRealRealMath)
  811.                     end;
  812.                 end;
  813.                 hlock(DataH);
  814.                 s2Data := rImagePtr(DataH^);
  815.                 isFFT := isFFT and (pos('FFT', title) = 1);
  816.             end;
  817.         with DstInfo^ do begin
  818.             hlock(DataH);
  819.             rData := rImagePtr(DataH^);
  820.             isFFT := isFFT and (pixelsPerLine = nlines) and isPowerOf2(pixelsPerLine);
  821.         end;
  822.         if isFFT and (src1Info^.PixelsPerLine = src2Info^.PixelsPerLine)
  823.             and (src1Info^.PixelsPerLine = src1Info^.nLines)
  824.             and (CurrentMathOp in [MulMath, cMulMath, DivMath]) then begin
  825.                 doFFTMath(Src1Info, Src2Info, DstInfo);
  826.                 exit(DoRealRealMath);
  827.             end;
  828.         with roi do begin
  829.                 ncols := right - left;
  830.                 nrows := bottom - top;
  831.                 hStart := left;
  832.                 vStart := top;
  833.             end;
  834.         StartTicks := TickCount;
  835.         NextUpdate:=TickCount+10;
  836.         min:=10e99;
  837.         max:=-10e99;
  838.         
  839.         for v := vStart to vStart + nRows - 1 do begin
  840.             base := v * ncols;
  841.             case CurrentMathOp of
  842.                 AddMath: 
  843.                     for h := 0 to nCols - 1 do begin
  844.                             x := s1Data^[base + h] + s2Data^[base + h];
  845.                             x := x * MathGain + MathOffset;
  846.                             rData^[base + h] := x;
  847.                             if x < min then
  848.                                 min := x;
  849.                             if x > max then
  850.                                 max := x;
  851.                         end;
  852.                 SubMath: 
  853.                     for h := 0 to nCols - 1 do begin
  854.                             x := s1Data^[base + h] - s2Data^[base + h];
  855.                             x := x * MathGain + MathOffset;
  856.                             rData^[base + h] := x;
  857.                             if x < min then
  858.                                 min := x;
  859.                             if x > max then
  860.                                 max := x;
  861.                         end;
  862.                 MulMath, cMulMath: 
  863.                     for h := 0 to nCols - 1 do begin
  864.                             x := s1Data^[base + h] * s2Data^[base + h];
  865.                             x := x * MathGain + MathOffset;
  866.                             rData^[base + h] := x;
  867.                             if x < min then
  868.                                 min := x;
  869.                             if x > max then
  870.                                 max := x;
  871.                         end;
  872.                 DivMath: 
  873.                     for h := 0 to nCols - 1 do begin
  874.                             x := s1Data^[base + h] / s2Data^[base + h];
  875.                             x := x * MathGain + MathOffset;
  876.                             rData^[base + h] := x;
  877.                             if x < min then
  878.                                 min := x;
  879.                             if x > max then
  880.                                 max := x;
  881.                         end;
  882.                 MaxMath: 
  883.                     for h := 0 to nCols - 1 do begin
  884.                             x1 := s1Data^[base + h];
  885.                             x2 := s2Data^[base + h];
  886.                             if x1 >= x2 then
  887.                                 x := x1
  888.                             else
  889.                                 x := x2;
  890.                             x := x * MathGain + MathOffset;
  891.                             rData^[base + h] := x;
  892.                             if x < min then
  893.                                 min := x;
  894.                             if x > max then
  895.                                 max := x;
  896.                         end;
  897.                 MinMath: 
  898.                     for h := 0 to nCols - 1 do begin
  899.                             x1 := s1Data^[base + h];
  900.                             x2 := s2Data^[base + h];
  901.                             if x1 <= x2 then
  902.                                 x := x1
  903.                             else
  904.                                 x := x2;
  905.                             x := x * MathGain + MathOffset;
  906.                             rData^[base + h] := x;
  907.                             if x < min then
  908.                                 min := x;
  909.                             if x > max then
  910.                                 max := x;
  911.                         end;
  912.                 CopyMath: 
  913.                     for h := 0 to nCols - 1 do begin
  914.                             x := s1Data^[base + h];
  915.                             x := x * MathGain + MathOffset;
  916.                             rData^[base + h] := x;
  917.                             if x < min then
  918.                                 min := x;
  919.                             if x > max then
  920.                                 max := x;
  921.                         end;
  922.             end; {case}
  923.             if TickCount >= NextUpdate then begin
  924.                 ShowAnimatedWatch;
  925.                 NextUpdate:=TickCount+10;
  926.                 if CommandPeriod then begin
  927.                         beep;
  928.                         AbortMacro;
  929.                         exit(DoRealRealMath)
  930.                     end;
  931.             end;
  932.         end; {for}
  933.         info := dstInfo;
  934.         if isFFT then begin
  935.             DisplayPowerSpectrum(rData);
  936.             SetFFTWindowName(false);
  937.         end else
  938.             DisplayRealImage(rData, min, max, false);
  939.         hunlock(src1Info^.dataH);
  940.         if CurrentMathOp <> copyMath then    
  941.             hunlock(src2Info^.dataH);        
  942.         hunlock(dstInfo^.dataH);        
  943.         ShowTime(StartTicks, roi, '');
  944.     end; {DoRealRealMath}
  945.  
  946.  
  947.  
  948.     procedure DoRealMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
  949.         var
  950.             nrows, ncols, hStart, vStart: LongInt;
  951.             Src1Info, Src2Info: InfoPtr;
  952.             h, v, i: LongInt;
  953.             src1, src2, dst: LineType;
  954.             tmp, tmp1, tmp2, StartTicks: LongInt;
  955.             SaveRow:LongInt;
  956.             NextUpdate: LongInt;
  957.             MaskRect:rect;
  958.             min, max, x, scale, x1, x2: extended;
  959.             BlackIsZero:boolean;
  960.             cvalue1, cvalue2: array[0..255] of extended;
  961.             rData: rImagePtr;
  962.             base: LongInt;
  963.  
  964.     begin
  965.         Src1Info := GetInfoPtr(Src1PicNum);
  966.         Src2Info := GetInfoPtr(Src2PicNum);
  967.         ShowWatch;
  968.         if DstInfo^.DataH = nil then begin
  969.             PutError('Output image must be real.');
  970.             exit(DoRealMath);
  971.         end;
  972.         if (src1Info^.dataH <> nil) or (src2Info^.dataH <> nil) then begin
  973.             doRealRealMath(Src1Info, Src2Info, DstInfo, roi);
  974.             exit(DoRealMath);
  975.         end;
  976.         with DstInfo^ do begin
  977.             if DataH = nil then
  978.                 exit(DoRealMath);
  979.             hlock(DataH);
  980.             rData := rImagePtr(DataH^);
  981.         end;
  982.         BlackIsZero:=((Src1Info^.fit=StraightLine) and (Src1Info^.coefficient[2]<0))
  983.                     or ((Src2Info^.fit=StraightLine) and (Src2Info^.coefficient[2]<0));
  984.         with roi do begin
  985.                 ncols := right - left;
  986.                 nrows := bottom - top;
  987.                 hStart := left;
  988.                 vStart := top;
  989.             end;
  990.         info := Src2Info;
  991.         GenerateValues;
  992.         for i:=0 to 255 do cvalue2[i]:=cvalue[i];
  993.         info := Src1Info;
  994.         GenerateValues;
  995.         for i:=0 to 255 do cvalue1[i]:=cvalue[i];
  996.         StartTicks := TickCount;
  997.         NextUpdate:=TickCount+10;
  998.         min:=10e99;
  999.         max:=-10e99;
  1000.         
  1001.         for v := vStart to vStart + nRows - 1 do begin
  1002.             info := Src1Info;
  1003.             GetLine(hStart, v, nCols, src1);
  1004.             Info := Src2Info;
  1005.             GetLine(hStart, v, nCols, src2);
  1006.             base := v * ncols;
  1007.             case CurrentMathOp of
  1008.                 AddMath: 
  1009.                     for h := 0 to nCols - 1 do begin
  1010.                             x := cvalue1[src1[h]] + cvalue2[src2[h]];
  1011.                             x := x * MathGain + MathOffset;
  1012.                             rData^[base + h] := x;
  1013.                             if x < min then
  1014.                                 min := x;
  1015.                             if x > max then
  1016.                                 max := x;
  1017.                         end;
  1018.                 SubMath: 
  1019.                     for h := 0 to nCols - 1 do begin
  1020.                             x := cvalue1[src1[h]] - cvalue2[src2[h]];
  1021.                             x := x * MathGain + MathOffset;
  1022.                             rData^[base + h] := x;
  1023.                             if x < min then
  1024.                                 min := x;
  1025.                             if x > max then
  1026.                                 max := x;
  1027.                         end;
  1028.                 MulMath, cMulMath: 
  1029.                     for h := 0 to nCols - 1 do begin
  1030.                             x := cvalue1[src1[h]] * cvalue2[src2[h]];
  1031.                             x := x * MathGain + MathOffset;
  1032.                             rData^[base + h] := x;
  1033.                             if x < min then
  1034.                                 min := x;
  1035.                             if x > max then
  1036.                                 max := x;
  1037.                         end;
  1038.                 DivMath: 
  1039.                     for h := 0 to nCols - 1 do begin
  1040.                             x := cvalue1[src1[h]] / cvalue2[src2[h]];
  1041.                             x := x * MathGain + MathOffset;
  1042.                             rData^[base + h] := x;
  1043.                             if x < min then
  1044.                                 min := x;
  1045.                             if x > max then
  1046.                                 max := x;
  1047.                         end;
  1048.                 MaxMath: 
  1049.                     for h := 0 to nCols - 1 do begin
  1050.                             x1 := cvalue1[src1[h]];
  1051.                             x2 := cvalue2[src2[h]];
  1052.                             if x1 >= x2 then
  1053.                                 x := x1
  1054.                             else
  1055.                                 x := x2;
  1056.                             x := x * MathGain + MathOffset;
  1057.                             rData^[base + h] := x;
  1058.                             if x < min then
  1059.                                 min := x;
  1060.                             if x > max then
  1061.                                 max := x;
  1062.                         end;
  1063.                 MinMath: 
  1064.                     for h := 0 to nCols - 1 do begin
  1065.                             x1 := cvalue1[src1[h]];
  1066.                             x2 := cvalue2[src2[h]];
  1067.                             if x1 <= x2 then
  1068.                                 x := x1
  1069.                             else
  1070.                                 x := x2;
  1071.                             x := x * MathGain + MathOffset;
  1072.                             rData^[base + h] := x;
  1073.                             if x < min then
  1074.                                 min := x;
  1075.                             if x > max then
  1076.                                 max := x;
  1077.                         end;
  1078.                 CopyMath: 
  1079.                     for h := 0 to nCols - 1 do begin
  1080.                             x := cvalue1[src1[h]];
  1081.                             x := x * MathGain + MathOffset;
  1082.                             rData^[base + h] := x;
  1083.                             if x < min then
  1084.                                 min := x;
  1085.                             if x > max then
  1086.                                 max := x;
  1087.                         end;
  1088.             end; {case}
  1089.             if TickCount >= NextUpdate then begin
  1090.                 ShowAnimatedWatch;
  1091.                 NextUpdate:=TickCount+10;
  1092.                 if CommandPeriod then begin
  1093.                         beep;
  1094.                         AbortMacro;
  1095.                         exit(DoRealMath)
  1096.                     end;
  1097.             end;
  1098.         end; {for}
  1099.         info := dstInfo;
  1100.         DisplayRealImage(rData, min, max, BlackisZero);
  1101.         hunlock(dstInfo^.dataH);        
  1102.         ShowTime(StartTicks, roi, '');
  1103.     end; {DoRealMath}
  1104.  
  1105.  
  1106.  
  1107.     procedure DoMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
  1108.         var
  1109.             nrows, ncols, hStart, vStart: integer;
  1110.             Src1Info, Src2Info: InfoPtr;
  1111.             h, v: integer;
  1112.             src1, src2, dst: LineType;
  1113.             tmp, tmp1, tmp2, StartTicks, scale, ScaledGain: LongInt;
  1114.             rtmp,rtmp2: extended;
  1115.             DoScaling: boolean;
  1116.             SaveRow:integer;
  1117.             NextUpdate: LongInt;
  1118.             MaskRect:rect;
  1119.             IntegerOffset: LongInt;
  1120.     begin
  1121.         if TooWide then
  1122.             exit(DoMath);
  1123.         if RealImageMath and not (CurrentMathOp in [AndMath, OrMath, XorMath]) then begin
  1124.             DoRealMath(Src1PicNum, Src2PicNum, DstInfo, roi);
  1125.             exit(DoMath);
  1126.         end;
  1127.         Src1Info := GetInfoPtr(Src1PicNum);
  1128.         Src2Info := GetInfoPtr(Src2PicNum);
  1129.         ShowWatch;
  1130.         with roi do begin
  1131.                 ncols := right - left;
  1132.                 nrows := bottom - top;
  1133.                 hStart := left;
  1134.                 vStart := top;
  1135.             end;
  1136.         StartTicks := TickCount;
  1137.         scale := 10000;
  1138.         ScaledGain := round(MathGain * scale);
  1139.         IntegerOffset := round(MathOffset);
  1140.         DoScaling := (MathGain <> 1.0) or (MathOffset <> 0.0);
  1141.         SaveRow:=vStart;
  1142.         NextUpdate:=TickCount+6; {Update screen 10 times per second}
  1143.         for v := vStart to vStart + nRows - 1 do begin
  1144.                 info := Src1Info;
  1145.                 GetLine(hStart, v, nCols, src1);
  1146.                 Info := Src2Info;
  1147.                 GetLine(hStart, v, nCols, src2);
  1148.                 case CurrentMathOp of
  1149.                     AddMath: 
  1150.                         for h := 0 to nCols - 1 do begin
  1151.                                 tmp := src1[h] + src2[h];
  1152.                                 tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1153.                                 if tmp > 255 then
  1154.                                     tmp := 255;
  1155.                                 if tmp < 0 then
  1156.                                     tmp := 0;
  1157.                                 dst[h] := tmp;
  1158.                             end;
  1159.                     SubMath: 
  1160.                         for h := 0 to nCols - 1 do begin
  1161.                                 tmp := src1[h] - src2[h];
  1162.                                 tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1163.                                 if tmp > 255 then
  1164.                                     tmp := 255;
  1165.                                 if tmp < 0 then
  1166.                                     tmp := 0;
  1167.                                 dst[h] := tmp;
  1168.                             end;
  1169.                     MulMath, cMulMath: 
  1170.                         for h := 0 to nCols - 1 do begin
  1171.                                 tmp := src1[h];
  1172.                                 tmp := tmp * src2[h];
  1173.                                 tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1174.                                 if tmp > 255 then
  1175.                                     tmp := 255;
  1176.                                 if tmp < 0 then
  1177.                                     tmp := 0;
  1178.                                 dst[h] := tmp;
  1179.                             end;
  1180.                     DivMath: 
  1181.                         for h := 0 to nCols - 1 do begin
  1182.                                 rtmp2:=src2[h];
  1183.                                 rtmp := src1[h] / rtmp2;
  1184.                                 tmp := round(rtmp * MathGain) + IntegerOffset;
  1185.                                 if tmp > 255 then
  1186.                                     tmp := 255;
  1187.                                 if tmp < 0 then
  1188.                                     tmp := 0;
  1189.                                 dst[h] := tmp;
  1190.                             end;
  1191.                     AndMath: 
  1192.                         for h := 0 to nCols - 1 do begin
  1193.                                 tmp := band(src1[h], src2[h]);
  1194.                                 if DoScaling then begin
  1195.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1196.                                         if tmp > 255 then
  1197.                                             tmp := 255;
  1198.                                         if tmp < 0 then
  1199.                                             tmp := 0;
  1200.                                     end;
  1201.                                 dst[h] := tmp;
  1202.                             end;
  1203.                     OrMath: 
  1204.                         for h := 0 to nCols - 1 do begin
  1205.                                 tmp := bor(src1[h], src2[h]);
  1206.                                 if DoScaling then begin
  1207.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1208.                                         if tmp > 255 then
  1209.                                             tmp := 255;
  1210.                                         if tmp < 0 then
  1211.                                             tmp := 0;
  1212.                                     end;
  1213.                                 dst[h] := tmp;
  1214.                             end;
  1215.                     XorMath: 
  1216.                         for h := 0 to nCols - 1 do begin
  1217.                                 tmp := bxor(src1[h], src2[h]);
  1218.                                 if DoScaling then begin
  1219.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1220.                                         if tmp > 255 then
  1221.                                             tmp := 255;
  1222.                                         if tmp < 0 then
  1223.                                             tmp := 0;
  1224.                                     end;
  1225.                                 dst[h] := tmp;
  1226.                             end;
  1227.                     MaxMath: 
  1228.                         for h := 0 to nCols - 1 do begin
  1229.                                 tmp1 := src1[h];
  1230.                                 tmp2 := src2[h];
  1231.                                 if tmp1 >= tmp2 then
  1232.                                     tmp := tmp1
  1233.                                 else
  1234.                                     tmp := tmp2;
  1235.                                 if DoScaling then begin
  1236.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1237.                                         if tmp > 255 then
  1238.                                             tmp := 255;
  1239.                                         if tmp < 0 then
  1240.                                             tmp := 0;
  1241.                                     end;
  1242.                                 dst[h] := tmp;
  1243.                             end;
  1244.                     MinMath: 
  1245.                         for h := 0 to nCols - 1 do begin
  1246.                                 tmp1 := src1[h];
  1247.                                 tmp2 := src2[h];
  1248.                                 if tmp1 <= tmp2 then
  1249.                                     tmp := tmp1
  1250.                                 else
  1251.                                     tmp := tmp2;
  1252.                                 if DoScaling then begin
  1253.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1254.                                         if tmp > 255 then
  1255.                                             tmp := 255;
  1256.                                         if tmp < 0 then
  1257.                                             tmp := 0;
  1258.                                     end;
  1259.                                 dst[h] := tmp;
  1260.                             end;
  1261.                     CopyMath: 
  1262.                         for h := 0 to nCols - 1 do begin
  1263.                                 tmp := src1[h];
  1264.                                 if DoScaling then begin
  1265.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1266.                                         if tmp > 255 then
  1267.                                             tmp := 255;
  1268.                                         if tmp < 0 then
  1269.                                             tmp := 0;
  1270.                                     end;
  1271.                                 dst[h] := tmp;
  1272.                             end;
  1273.                 end;
  1274.                 Info := DstInfo;
  1275.                 PutLine(0, v - vstart, nCols, Dst);
  1276.                 if TickCount>=NextUpdate then begin
  1277.                     SetRect(MaskRect, hStart, SaveRow, hStart+ncols, v + 1);
  1278.                     UpdateScreen(MaskRect);
  1279.                     SaveRow:=v+1;
  1280.                     NextUpdate:=TickCount+6;
  1281.                     ShowAnimatedWatch;
  1282.                     if CommandPeriod then begin
  1283.                             UpdateScreen(info^.RoiRect);
  1284.                             beep;
  1285.                             AbortMacro;
  1286.                             exit(DoMath)
  1287.                         end;
  1288.                 end;
  1289.             end;
  1290.         with info^ do begin
  1291.                 ShowTime(StartTicks, RoiRect, '');
  1292.                 SetRect(MaskRect, hStart, SaveRow, hStart+ncols, vStart+nRows);
  1293.                 UpdateScreen(MaskRect);
  1294.                 Changes := true;
  1295.                 RemoveDensityCalibration;
  1296.             end;
  1297.     end; {DoMath}
  1298.  
  1299.  
  1300.     function ImageTitle (var PicNumber: integer): str255;
  1301.         var
  1302.             TempInfo: InfoPtr;
  1303.     begin
  1304.         if (PicNumber < 1) or (PicNumber > nPics) then
  1305.             PicNumber := 1;
  1306.         TempInfo := pointer(WindowPeek(PicWindow[PicNumber])^.RefCon);
  1307.         ImageTitle := TempInfo^.title;
  1308.     end;
  1309.  
  1310.  
  1311.     procedure ImageMathUProc (d: DialogPtr; item: integer);
  1312.      {User proc for Image Math dialog box}
  1313.         const
  1314.             ops = '';
  1315.         var
  1316.             str: str255;
  1317.             VersInfo: str255;
  1318.             r: rect;
  1319.     begin
  1320.         SetPort(d);
  1321.         GetDItemRect(d, item, r);
  1322.         DrawDropBox(r);
  1323.         case item of
  1324.             Src1Item: 
  1325.                 DrawPopUpText(ImageTitle(MathSrc1), r);
  1326.             Src2Item: 
  1327.                 DrawPopUpText(ImageTitle(MathSrc2), r);
  1328.             OpItem:  begin
  1329.                     GetMenuItemText(ImageMathOpsMenuH, ord(CurrentMathOp) + 1, str);
  1330.                     DrawPopUpText(str, r);
  1331.                 end;
  1332.         end;
  1333.     end;
  1334.  
  1335.  
  1336.     function PopUpImageList (r: rect; CurrentImage: integer): integer;
  1337.         var
  1338.             i: integer;
  1339.     begin
  1340.         for i := 1 to nPics do begin
  1341.                 AppendMenu(ImageListMenuH, ' ');
  1342.                 SetMenuItemText(ImageListMenuH, i, ImageTitle(i));
  1343.             end;
  1344.         PopUpImageList := PopUpMenu(ImageListMenuH, r.left, r.top, CurrentImage);
  1345.         for i := 1 to nPics do
  1346.             DeleteMenuItem(ImageListMenuH, 1);
  1347.     end;
  1348.  
  1349.  
  1350.     procedure DoImageMath;
  1351.         const
  1352.             ScaleItem = 10;
  1353.             OffSetMenuItemText = 11;
  1354.             ResultItem = 12;
  1355.             RealMathItem=14;
  1356.         var
  1357.             d: DialogPtr;
  1358.             item, i, MenuItem: integer;
  1359.             r: rect;
  1360.             str: str255;
  1361.             ScaleOffEdited: boolean;
  1362.             roi:rect;
  1363.             DstInfo:InfoPtr;
  1364.  
  1365.         procedure ShowScaleAndOffset;
  1366.         begin
  1367.             SetDReal(d, ScaleItem, MathGain, 4);
  1368.             if RealImageMath then
  1369.                 SetDReal(d, OffSetMenuItemText, MathOffset, 2)
  1370.             else
  1371.                 SetDNum(d, OffSetMenuItemText, round(MathOffset));
  1372.         end;
  1373.  
  1374.         procedure ResetScaleOff;
  1375.         begin
  1376.             if not ScaleOffEdited then begin
  1377.                     MathGain := 1.0;
  1378.                     MathOffset := 0.0;
  1379.                     ShowScaleAndOffset;
  1380.                 end;
  1381.         end;
  1382.  
  1383.         procedure CheckForRealImage(picNum: integer);
  1384.         var
  1385.             srcInfo:InfoPtr;
  1386.         begin
  1387.             srcInfo := GetInfoPtr(picNum);
  1388.             if srcInfo^.dataH <> nil then begin
  1389.                 RealImageMath := true;
  1390.                 SetDlogItem(d, RealMathItem, ord(RealImageMath));
  1391.             end;
  1392.         end;
  1393.     
  1394.     begin
  1395.         if ImageMathUserProc=nil
  1396.             then ImageMathUserProc:=NewRoutineDescriptor(@ImageMathUProc, uppUserItemProcInfo, GetCurrentISA);
  1397.         InitCursor;
  1398.         ScaleOffEdited := false;
  1399.         d := GetNewDialog(200, nil, pointer(-1));
  1400.         SetUProc(d, Src1Item, handle(ImageMathUserProc));
  1401.         SetUProc(d, Src2Item, handle(ImageMathUserProc));
  1402.         SetUProc(d, OpItem, handle(ImageMathUserProc));
  1403.         ShowScaleAndOffset;
  1404.         SetDString(d, ResultItem, MathResult);
  1405.         SetDlogItem(d, RealMathItem, ord(RealImageMath));
  1406.         if (MathSrc1 = 1) and (MathSrc2 = 1) then
  1407.             MathSrc1 := info^.PicNum;
  1408.         if MathSrc1 = MathSrc2 then begin
  1409.                 if MathSrc1 = info^.PicNum then begin
  1410.                         MathSrc2 := MathSrc2 + 1;
  1411.                         if MathSrc2 > nPics then
  1412.                             MathSrc2 := 1;
  1413.                     end
  1414.                 else
  1415.                     MathSrc2 := info^.PicNum;
  1416.             end;
  1417.         CheckForRealImage(MathSrc1);
  1418.         CheckForRealImage(MathSrc2);
  1419.         repeat
  1420.             ModalDialog(nil, item);
  1421.             if item = Src1Item then begin
  1422.                     setport(d);
  1423.                     GetDItemRect(d, item, r);
  1424.                     MenuItem := PopUpImageList(r, MathSrc1);
  1425.                     if MenuItem <> 0 then
  1426.                         MathSrc1 := MenuItem;
  1427.                     CheckForRealImage(MathSrc1);
  1428.                     InvalRect(r);
  1429.                 end;
  1430.             if item = Src2Item then begin
  1431.                     setport(d);
  1432.                     GetDItemRect(d, item, r);
  1433.                     MenuItem := PopUpImageList(r, MathSrc2);
  1434.                     if MenuItem <> 0 then
  1435.                         MathSrc2 := MenuItem;
  1436.                     CheckForRealImage(MathSrc2);
  1437.                     InvalRect(r);
  1438.                 end;
  1439.             if item = OpItem then begin
  1440.                     setport(d);
  1441.                     GetDItemRect(d, item, r);
  1442.                     MenuItem := PopUpMenu(ImageMathOpsMenuH, r.left, r.top, ord(CurrentMathOp) + 1);
  1443.                     case MenuItem of
  1444.                         1:  begin
  1445.                                 CurrentMathOp := AddMath;
  1446.                                 if not ScaleOffEdited then begin
  1447.                                         if RealImageMath then
  1448.                                             ResetScaleOff
  1449.                                         else begin
  1450.                                             MathGain := 0.5;
  1451.                                             MathOffset := 0.0;
  1452.                                             ShowScaleAndOffset;
  1453.                                         end;
  1454.                                     end;
  1455.                             end;
  1456.                         2:  begin
  1457.                                 CurrentMathOp := SubMath;
  1458.                                 if not ScaleOffEdited then begin
  1459.                                         if RealImageMath then
  1460.                                             ResetScaleOff
  1461.                                         else begin
  1462.                                             MathGain := MathSubGain;
  1463.                                             MathOffset := MathSubOffset;
  1464.                                             ShowScaleAndOffset;
  1465.                                         end;
  1466.                                     end;
  1467.                             end;
  1468.                         3:  begin
  1469.                                 CurrentMathOp := MulMath;
  1470.                                 if not ScaleOffEdited then begin
  1471.                                         if RealImageMath then
  1472.                                             ResetScaleOff
  1473.                                         else begin
  1474.                                             MathGain := 1.0 / 255.0;
  1475.                                             MathOffset := 0.0;
  1476.                                             ShowScaleAndOffset;
  1477.                                         end;
  1478.                                     end;
  1479.                             end;
  1480.                         4:  begin
  1481.                                 CurrentMathOp := DivMath;
  1482.                                 if not ScaleOffEdited then begin
  1483.                                         if RealImageMath then
  1484.                                             ResetScaleOff
  1485.                                         else begin
  1486.                                             MathGain := 255.0;
  1487.                                             MathOffset := 0.0;
  1488.                                             ShowScaleAndOffset;
  1489.                                         end;
  1490.                                     end;
  1491.                             end;
  1492.                         5:  begin
  1493.                                 CurrentMathOp := AndMath;
  1494.                                 ResetScaleOff;
  1495.                             end;
  1496.                         6:  begin
  1497.                                 CurrentMathOp := OrMath;
  1498.                                 ResetScaleOff;
  1499.                             end;
  1500.                         7:  begin
  1501.                                 CurrentMathOp := XorMath;
  1502.                                 ResetScaleOff;
  1503.                             end;
  1504.                         8:  begin
  1505.                                 CurrentMathOp := MaxMath;
  1506.                                 ResetScaleOff;
  1507.                             end;
  1508.                         9:  begin
  1509.                                 CurrentMathOp := MinMath;
  1510.                                 ResetScaleOff;
  1511.                             end;
  1512.                         10:    begin
  1513.                                 CurrentMathOp := cMulMath;
  1514.                                 ResetScaleOff;
  1515.                             end;
  1516.                         11:    begin
  1517.                                 CurrentMathOp := CopyMath;
  1518.                                 ResetScaleOff;
  1519.                             end;
  1520.                         otherwise
  1521.                     end;
  1522.                     InvalRect(r);
  1523.                 end;
  1524.             if item = ScaleItem then begin
  1525.                     MathGain := GetDReal(d, ScaleItem);
  1526.                     ScaleOffEdited := true;
  1527.                 end;
  1528.             if item = OffSetMenuItemText then begin
  1529.                     MathOffset := GetDReal(d, OffSetMenuItemText);
  1530.                     ScaleOffEdited := true;
  1531.                 end;
  1532.             if item = RealMathItem then begin
  1533.                     RealImageMath := not RealImageMath;
  1534.                     SetDlogItem(d, RealMathItem, ord(RealImageMath));
  1535.                     ResetScaleOff;
  1536.                 end;
  1537.         until (item = ok) or (item = cancel);
  1538.         MathResult := GetDString(d, ResultItem);
  1539.         DisposeDialog(d);
  1540.         if item = cancel then
  1541.             exit(DoImageMath);
  1542.         if not GetMathRoi(MathSrc1, MathSrc2, roi) then
  1543.             exit(DoImageMath);
  1544.         with roi do
  1545.             if RealImageMath then begin
  1546.                 if not NewRealWindow(MathResult, right-left, bottom-top) then
  1547.                     exit(DoImageMath)
  1548.             end else begin
  1549.                 if not NewPicWindow(MathResult, right-left, bottom-top) then
  1550.                     exit(DoImageMath)
  1551.             end;
  1552.         DstInfo := Info;
  1553.         DoMath(MathSrc1, MathSrc2, DstInfo, roi);
  1554.         if CurrentMathOp=SubMath then begin
  1555.             MathSubGain:=MathGain;
  1556.             MathSubOffset:=MathOffset;
  1557.         end;
  1558.     end;
  1559.  
  1560.  
  1561.  
  1562. end.